package javawdw.xml.jaxb;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;

/**
 * base jdk1.6
 * @author 王大卫
 *
 */
public class JaxbCodec {
	private Map<Class<?>, JAXBContext> contextMap;
	private Map<Class<?>, Unmarshaller> unmarshallerMap;
	private Map<Class<?>, Marshaller> marshallerMap;

	public JaxbCodec() {
		this.contextMap = new HashMap<Class<?>, JAXBContext>();
		this.unmarshallerMap = new HashMap<Class<?>, Unmarshaller>();
		this.marshallerMap = new HashMap<Class<?>, Marshaller>();
	}

	public <E> E xml2Obj(InputStream xml, Class<E> objclass)
			throws JAXBException, IOException {
		JAXBElement<E> jaxbElement = null;
		Unmarshaller unmarshaller = unmarshallerMap.get(objclass);
		JAXBContext jaxbContext = contextMap.get(objclass);
		if (unmarshaller == null) {
			Object tempObject = null;
			try {
				tempObject = objclass.newInstance();
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
			if (jaxbContext == null) {
				jaxbContext = JAXBContext.newInstance(tempObject.getClass());
				contextMap.put(objclass, jaxbContext);
			}
			unmarshaller = jaxbContext.createUnmarshaller();
		}
		Reader reader = null;
		try {
			reader = new InputStreamReader(xml, "utf-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		StreamSource source = new StreamSource(reader);
		jaxbElement = unmarshaller.unmarshal(source, objclass);
		reader.close();
		return jaxbElement.getValue();
	}

	public void obj2Xml(Object instance, OutputStream outputStream,
			boolean formatOutput) throws JAXBException, IOException {
		Class<?> instanceClass = instance.getClass();
		Marshaller marshaller = marshallerMap.get(instanceClass);
		JAXBContext jaxbContext = contextMap.get(instanceClass);
		if (marshaller == null) {
			if (jaxbContext == null) {
				jaxbContext = JAXBContext.newInstance(instanceClass);
				contextMap.put(instanceClass, jaxbContext);
			}
			marshaller = jaxbContext.createMarshaller();
		}
		Writer writer = null;
		try {
			writer = new OutputStreamWriter(outputStream, "UTF-8");
			marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
					formatOutput);
			marshaller.marshal(instance, writer);
			writer.close();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
	}
}